<?php
/**
 * 基础类
 * @author JohnnyDen <413819942@qq.com>
 * @package Api\Controller
 * @copyright 2018年11月12日
 */
namespace api;

use think\Controller;

class Api extends Controller {
    
    /**
     * 需要验证的方法：null(禁止访问) |true(验证所有) | false(无需验证) | []
     * [
     *      //无权访问的action
     *      'no_access' => [],
     *      //需要验证的action
     *      'auth'      => [],
     *      //不需要在验证的action
     *      'no_auth'   => [],
     *      //以上都未匹配到时，默认：null | true | false
     *      '_default'  => null,
     * ];
     */
    protected $authAnonymousMethods = true;
    
    //授权用户验证
    protected $authUserMethods      = false;
    
    //
    /**
     * 通信加密级别，1 ~ 10，越需要加密的，级别设定越高
     * @var integer
     * [
     *      //方法名 为key，对方法定义级别
     *      'login'     => 10,
     * ];
     */
    protected $cryptLevel           = 0;
    
    //用户信息
    private $_user    = null;
    
    //服务信息
    private $_serviceInfo   = null;
    
    /**
     * 验签及用户access_token校验
     * @return boolean
     */
    public function _initialize() {
        $request    = \think\Request::instance();
        config('__CONTROLLER_NAME__', $request->controller());
        config('__ACTION_NAME__', $request->action(true));
        
        //验证应用程序
        $is_auth = $this->_authClientRequest($_GET['sign'], $_GET['client_id'], $_GET['timestamp'], [
            'crypt_level'   => $_GET['crypt_level'],
        ]);
        
        //验证用户
        if ($is_auth) {
            $is_auth = $this->_authUser( $_GET['access_token'] );
        }
        
        return true;
    }
    
    /**
     * 验证应用程序请求
     * @param string $sign 签名
     * @param number $id_client 终端程序ID
     * @param number $timestamp 请求时间
     * @param array $sign_params 请求的其它参数
     * @return boolean 是否执行了验证
     */
    private function _authClientRequest($sign, $id_client, $timestamp, $sign_params) {
        if ($this->authAnonymousMethods === null) {
            out('no_access_request');
        }
        if ($need_auth = $this->_needAuth( $this->authAnonymousMethods )) {
            if (!$sign) {
                out('empty_sign');
            }
            if (!$id_client) {
                out('empty_id_client');
            }
            if (!\api\Auth::checkSign($sign, $id_client, $timestamp, $sign_params)) {
                out('error_sign', null, [$sign]);
            }
            
            //解密
            $action_crypt_level = is_array($this->cryptLevel) ? $this->cryptLevel[config('__ACTION_NAME__')] : $this->cryptLevel;
            $check  = \api\Auth::checkCryptLevel($sign_params['crypt_level'], $action_crypt_level);
            if ( null === $check ) {
                out('error_crypt_level');
            } else if ($check) {
                $data   = \api\Auth::decrypt(in('key'), in('data'));
                in($data);
            }
        }
        
        return $need_auth;
    }
    
    /**
     * 判断当前请求是否需要验证
     * @param array $auth_methods 验证规则集
     * @return null | boolean 是否需要验证
     */
    private function _needAuth(&$auth_methods) {
        if (!is_array($auth_methods)) {
            return $auth_methods;
        } else {
            if ($auth_methods['no_access'] && in_array(config('__ACTION_NAME__'), $auth_methods['no_access'])) {
                return true;
            } else if ($auth_methods['auth'] && in_array(config('__ACTION_NAME__'), $auth_methods['auth'])) {
                return true;
            } else if ($auth_methods['no_auth'] && in_array(config('__ACTION_NAME__'), $auth_methods['no_auth'])) {
                return false;
            }
            
            return $auth_methods['_default'];
        }
    }
    
    /**
     * 验证用户
     * @param string $access_token
     * @param number $id_client
     * @return boolean 是否执行了验证
     */
    private function _authUser($access_token) {
        if ($this->_needAuth( $this->authUserMethods ) === false) {
            return false;
        }
        
        //access_token验证用户
        if (!$access_token) {
            out('no_access');
        }
        $this->_user = $this->_auth($access_token);
        if (!$this->_user) {
            out('error_access_token');
        }
        
        return true;
    }
    
    /**
     * access_token有效验证
     * @param string $access_token
     * @param number $id_client
     * @return false | array
     */
    private function _auth($access_token) {
        if ($access_token) {
            $token  = db('UserAccessToken')->field('uid,expire_time,upd_time,login_id_xpp_user')->where('access_token', $access_token)->find();
        }
        
        $time   = time();
        if (!$token || ($token['expire_time'] && $token['expire_time'] <= $time)) {
            return false;
        }
        unset($token['expire_time']);
        if ($time - $token['upd_time'] > 120) {
            db('UserAccessToken')->where('access_token', $access_token)->setField('upd_time', $time);
        }
        return $token;
    }
    
    /**
     * 快捷获取分页数据结构数组
     * @param string $default_order 默认排序参数
     * @param number $default_p_rows 默认每页显示记录数
     * @return array
     * <code>
     * [
     *      'p'         => 1,
     *      'p_rows'    => 20,
     *      'sort'      => '',
     *      'total_rows'=> 0,
     *      'list'      => [],
     * ];
     * </code>
     */
    protected function quickPage($default_order = '', $default_p_rows = 20) {
        $page_arr   = in('page_arr/a');
        
        $result = [
            'p'     => $page_arr['p'],
            'p_rows'=> $page_arr['p_rows'],
            'order' => $page_arr['order'],
            'total_rows'    => 0,
            'list'          => [],
        ];
        
        if (!$result['p']) {
            $result['p']        = 1;
        }
        if (!$result['p_rows']) {
            $result['p_rows']   = $default_p_rows;
        }
        if (!$result['order']) {
            $result['order']    = $default_order;
        }
        
        return $result;
    }
    
    /*****以下内容为业务公用方法*****/
    
    /**
     * 获取用户信息
     * @param string $field 字段名称
     * @return mixed
     */
    protected function user($field) {
        if ($field && !isset($this->_user[$field])) {
            if ($field == 'xpp_auth') {
                $this->_user[$field]    = db('UserRXpp')->field('id_xpp_user as xpp_id_user,uid,secret')->where('uid', $this->_user['uid'])->find();
            } else {
                $user   = db('Users')->field('uid,username,nickname,password,salt')->where('uid', $this->_user['uid'])->find();
                $this->_user    = array_merge($this->_user, $user);
            }
        }
        return $this->_user[$field];
    }
}